/**
 * 文件名: memory_order_examples_test.cpp
 *
 * 构建与运行（示例命令，需已安装 GoogleTest）：
 *   g++ -std=c++20 -pthread memory_order_examples_test.cpp -lgtest -lgtest_main -o memory_order_examples_test
 *   ./memory_order_examples_test
 *
 * 示例目标：
 *   1. 通过 release/acquire 展示“发布—消费”模型下的数据可见性。
 *   2. 演示 relaxed 内存序在纯统计场景中的高效原子计数。
 *   3. 使用 compare_exchange_strong 配合 acq_rel/acquire 构建无锁状态机，并验证只有一次成功的状态转换。
 */

#include <gtest/gtest.h>

#include <atomic>
#include <thread>
#include <vector>

// -----------------------------------------------------------------------------
// 1. release / acquire 示例
// -----------------------------------------------------------------------------
TEST(MemoryOrderTest, ReleaseAcquirePublishesPayload) {
    std::atomic<bool> ready{false};  // 共享标志，表示 payload 是否已准备好
    int payload = 0;                 // 共享数据，由生产者写入，消费者读取

    std::thread producer([&] {
        payload = 42;  // (1) 普通写，先更新数据内容

        // (2) 以 release 语义写入标志位。
        //     这会禁止 (1) 被重排到 store 之后，从而保证消费者读取 ready==true 时，
        //     能看到 payload 的修改。
        ready.store(true, std::memory_order_release);
    });

    std::thread consumer([&] {
        // (3) 不断轮询 ready。使用 acquire 语义可以阻止后续读写移动到 load 之前。
        while (!ready.load(std::memory_order_acquire)) {
            std::this_thread::yield();  // 防止忙等耗费过多 CPU
        }

        // (4) 一旦跳出循环，acquire 语义保证我们观察到的 payload == 42。
        EXPECT_EQ(payload, 42);
    });

    producer.join();
    consumer.join();
}

// -----------------------------------------------------------------------------
// 2. relaxed 示例
// -----------------------------------------------------------------------------
TEST(MemoryOrderTest, RelaxedCounterAccumulatesCorrectly) {
    std::atomic<int> counter{0};              // 共享计数器
    constexpr int kThreadCount = 8;           // 并发线程数量
    constexpr int kIncrementsPerThread = 50000;  // 每个线程执行自增的次数

    auto worker = [&]() {
        for (int i = 0; i < kIncrementsPerThread; ++i) {
            // 使用 relaxed：只保证 fetch_add 的原子性，不提供额外的同步语义。
            // 适用于纯统计场景，不依赖该计数器与其他数据之间的顺序关系。
            counter.fetch_add(1, std::memory_order_relaxed);
        }
    };

    std::vector<std::thread> threads;
    threads.reserve(kThreadCount);

    // 启动多个线程并行执行计数
    for (int i = 0; i < kThreadCount; ++i) {
        threads.emplace_back(worker);
    }
    for (auto& t : threads) {
        t.join();
    }

    // 对最终值进行验证：所有线程的自增次数累计之和
    EXPECT_EQ(counter.load(std::memory_order_relaxed),
              kThreadCount * kIncrementsPerThread);
}

// -----------------------------------------------------------------------------
// 3. CAS + acq_rel 示例
// -----------------------------------------------------------------------------

// 状态机的三种状态：Idle（空闲）、Processing（处理中）、Done（完成）。
enum class JobState { Idle, Processing, Done };

TEST(MemoryOrderTest, CompareExchangeCoordinatesState) {
    std::atomic<JobState> state{JobState::Idle};  // 共享状态
    std::atomic<int> startedCount{0};             // 成功进入 Processing 的次数
    std::atomic<int> doneCount{0};                // 成功完结的次数

    auto attempt_start = [&] {
        // 初始期望状态：Idle。compare_exchange 会在失败时写回真实状态。
        JobState expected = JobState::Idle;

        // (1) 尝试从 Idle 切换到 Processing。
        //     - 成功路径使用 acq_rel：既读取当前状态，又发布修改。
        //     - 失败路径使用 acquire：读取到别人发布的最新状态。
        if (state.compare_exchange_strong(expected, JobState::Processing,
                                          std::memory_order_acq_rel,
                                          std::memory_order_acquire)) {
            // (2) 只有一个线程会走到这里：它抢到了“任务”。
            startedCount.fetch_add(1, std::memory_order_relaxed);

            // 模拟执行任务，之后切换到 Done。
            expected = JobState::Processing;
            bool finished = state.compare_exchange_strong(expected, JobState::Done,
                                                          std::memory_order_acq_rel,
                                                          std::memory_order_acquire);
            if (finished) {
                doneCount.fetch_add(1, std::memory_order_relaxed);
            } else {
                // 理论上不应该失败：只有成功线程才能从 Processing → Done。
                ADD_FAILURE() << "Unexpected state transition failure";
            }
        } else {
            // (3) 抢占失败的线程：expected 被 compare_exchange 更新为真实状态，
            //     该状态必然不是 Idle（可能是 Processing 或 Done）。
            EXPECT_NE(expected, JobState::Idle);
        }
    };

    // 启动多个线程竞争同一状态
    std::vector<std::thread> workers;
    for (int i = 0; i < 6; ++i) {
        workers.emplace_back(attempt_start);
    }
    for (auto& t : workers) {
        t.join();
    }

    // (4) 断言：仅有一个线程成功启动任务并完成。
    EXPECT_EQ(startedCount.load(std::memory_order_relaxed), 1);
    EXPECT_EQ(doneCount.load(std::memory_order_relaxed), 1);

    // (5) 最终状态应该为 Done，使用 acquire 读取以保证观察到一致状态。
    EXPECT_EQ(state.load(std::memory_order_acquire), JobState::Done);
}